#ifndef WORLDB_H
#define WORLDB_H

#include "BulletMultiThreaded/PosixThreadSupport.h"
#include "BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
#include "BulletMultiThreaded/SpuGatheringCollisionDispatcher.h"
#include "BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.h"
#include "BulletMultiThreaded/btParallelConstraintSolver.h"
#include "btBulletDynamicsCommon.h"
// #include <omp.h>
#include <iomanip>

#include <GL/glew.h>

#ifdef HAVE_OPENCL
// 	#include "clnbody.h"
// 	#include "../../cl/clcontext.h"
#endif

#include "src/utils/dir.h"
#include "src/common/be_parser.h"
#include "src/utils/settings.h"
#include "src/utils/raycast.h"
#include "src/common/be_mouse_picker.h"
#include "src/utils/statsbuffer.h"
#include "src/utils/logbuffer.h"
#include "src/utils/dirlayout.h"
#include "src/common/be_rand.h"
#include "src/common/be_frame_limiter.h"

#include "../gui/textverbosemessage.h"

#include "critterselection.h"
#include "food.h"
#include "wall.h"
#include "critterb.h"
#include "src/graphics/be_camera.h"
#include "src/graphics/be_graphics_system.h"

using namespace std;




class WorldB
{
	class	btThreadSupportInterface*		m_threadSupportCollision;
	class	btThreadSupportInterface*		m_threadSupportSolver;

	public:
		WorldB( Textverbosemessage* textverbosemessage );
		virtual			~WorldB();
		virtual void		init();
		virtual void		process(unsigned long long frameCounter);
		virtual void		process_prephysics(unsigned long long frameCounter);
		virtual void		process_postphysics(unsigned long long frameCounter);
		virtual btVector3	findPosition();
		virtual			void makeFloor();
		bool 			pause;
		bool			mouselook;

		float			insertHight;
		void			getGeneralStats();
		void			killHalf();
		void			expireFood();
		void			expireCritters();
		void			autoinsertFood();
		void			autosaveCritters();
		void			autoexchangeCritters();
		void			autoinsertCritters();
		void			procreate( CritterB* c );
		void			makeDefaultFloor();
		
		Settings*		settings;
		Critterselection	*critterselection;
		Statsbuffer*		statsBuffer;
		BeRand*			randgen;
		BeMousePicker*		mousepicker;
		Dirlayout*		dirlayout;
// 		BeCamera		camera;
		BeCameraPerspective	m_camera;
		BeSceneNode		m_sceneNodeCamera;
		void resetCamera();
		unsigned int		findEntityIndex( unsigned int number, entityType et );

		btCollisionDispatcher*	m_dispatcher;
		btBroadphaseInterface*	m_broadphase;
		btDefaultCollisionConfiguration* m_collisionConfiguration;
		btDynamicsWorld*	m_dynamicsWorld;
		btConstraintSolver*	m_solver;
		btAlignedObjectArray<btCollisionShape*>	m_collisionShapes;
    static void CollisionNearOverride(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo);

		vector<CritterB*>	critters;
		vector<Entity*>		entities;

		unsigned long		currentCritterID;

		float			freeEnergy;

		virtual void		drawWithGrid();
		
		virtual void		drawfloor();
		virtual void		childPositionOffset(btVector3* v);

		void			startfoodamount(unsigned int amount);

		void			insertRandomFood(int amount, float energy);

		virtual void		insertCritter();
		void			saveAllCritters();
		virtual void		loadAllCritters();
		virtual void		loadAllLastSavedCritters();
		BeFrameLimiter		framelimiter;

		void			removeSelectedCritter();
		void			removeAllSelectedCritters();
		void			duplicateCritter(unsigned int cid, bool brainmutant, bool bodymutant);

		void			duplicateSelectedCritter();
		void			spawnBrainMutantSelectedCritter();
		void			spawnBodyMutantSelectedCritter();
		void			spawnBrainBodyMutantSelectedCritter();
		void			feedSelectedCritter();
		void			resetageSelectedCritter();

		void			duplicateAllSelectedCritters();
		void			spawnBrainMutantAllSelectedCritters();
		void			spawnBodyMutantAllSelectedCritters();
		void			spawnBrainBodyMutantAllSelectedCritters();

		void			killHalfOfCritters();
		void			togglePause();
// 		void			toggleSleeper();
		void			toggleMouselook();

		void			pickBody();
		void			unpickBody();
		void			selectBody();
		void			deselectBody();
		void			castMouseRay();
		void			movePickedBodyTo();
		void			movePickedBodyFrom();
		float			autosaveCounter;
		float			autoexchangeCounter;

		const unsigned int*	critter_maxenergy;
    const unsigned int* critter_retinasize;
		const unsigned int*	worldsizeX;
		const unsigned int*	worldsizeY;
		const unsigned int*	headless;
		const unsigned int*	threads;

		void			calcMouseDirection();
		void			moveInMouseDirection(bool towards);

		Dir			dirH;
		BeParser		parseH;

		bool			mouseRayHit;
		Entity*			mouseRayHitEntity;

		// pointers to parents (evolution) mousepos
		int mousex;
		int mousey;
// 		int relx;
// 		int rely;
		
		// threading
// 		omp_lock_t my_lock1;
		BeGraphicsSystem m_graphicsSystem;

	protected:
		Textverbosemessage*	m_textverbosemessage;
	private:
		Raycast*		raycast;

#ifdef HAVE_OPENCL
// 		CLNBody nbody;
#endif

		castResult		mouseRay;
		btVector3		mouseRayTo;
		
		
		unsigned int		insertCritterCounter;


		// methods
		inline void		removeCritter(unsigned int cid);
// 		inline void		createDirs();

		// Settings pointers.. performance
		const unsigned int*	critter_maxlifetime;
		const unsigned int*	critter_autosaveinterval;
		const unsigned int*	critter_autoexchangeinterval;
		const unsigned int*	critter_killhalfat;
		const unsigned int*	critter_sightrange;
		const unsigned int*	critter_enableomnivores;

		const unsigned int*	brain_mutationrate;
		const unsigned int*	body_mutationrate;

		const unsigned int*	killhalf_decrenergypct;
		const unsigned int*	killhalf_incrworldsizeX;
		const unsigned int*	killhalf_incrworldsizeY;
		const unsigned int*	killhalf_decrmaxlifetimepct;

		const unsigned int*	food_maxlifetime;
		const unsigned int*	food_maxenergy;
		const unsigned int*	energy;
		const unsigned int*	mincritters;
		const unsigned int*	insertcritterevery;



		const unsigned int*	critter_startenergy;


		
		btManifoldArray   manifoldArray;

		int			findSelectedCritterID();
		int			findCritterID(unsigned int cid);
};

#endif
